package com.cy.chatTest.controller;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import com.cy.chatTest.bin.MessageType;
import com.cy.chatTest.db.*;
import com.google.gson.Gson;
import org.springframework.stereotype.Service;

@Service
public class SocketTest {

    static ServerSocket sSocket;
    static ArrayList<UserSocket> userSocketList = new ArrayList<>();


    static UserSocket getUserSocketByIp(String ip) {
        for (UserSocket us : SocketTest.userSocketList) {
            if (ip.equals(us.inetAddress.getHostAddress())) {
                return us;
            }
        }
        return null;
    }

    static UserSocket getUserSocketByUsername(String email) {
        for (UserSocket us : SocketTest.userSocketList) {
            if (email.equals(us.userInfo.getUsername())) {
                return us;
            }
        }
        return null;
    }


    public static void mainRun() {

        try {
            String ip = InetAddress.getLocalHost().getHostAddress().toString();
            System.out.println("服务器ip:" + ip);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        System.out.println("服务器启动");

        try {
            sSocket = new ServerSocket(10986);
            while (true) {
                final Socket socket = sSocket.accept();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        new UserSocket(socket);
                    }
                }).start();
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            System.out.println("服务崩溃了");
            e.printStackTrace();
        }

    }


    /**
     * 将该连接的用户的通讯录完整发过去
     *
     * @param userSocket
     */
    public static void sendContactsList(UserSocket userSocket) {
        ArrayList<String> emails = userSocket.userInfo.getContactsList();
        ArrayList<UserInfo> contacts = new ArrayList<>();
        for (String username : emails) {
            contacts.add(DbUtil.getInstance().userInfoRepository.findByUsername(username));
        }
        MessageInfo ips = new MessageInfo(MessageType.ALL_FRIEND, new Gson().toJson(contacts));
        userSocket.sendMessage(ips);

    }

    /**
     * 将离线消息发送过去
     *
     * @param userSocket
     */
    public static void sendUnreadMsgList(UserSocket userSocket) {
        List<MessageInfo> unReadMsgList = DbUtil.getInstance().messageInfoRepository.findMessageInfosByToUsername(userSocket.userInfo.getUsername());
        if (unReadMsgList != null && !unReadMsgList.isEmpty()) {
            MessageInfo unReadMsgs = new MessageInfo(MessageType.UNREAD_MSGS, new Gson().toJson(unReadMsgList));
            userSocket.sendMessage(unReadMsgs);
        }

    }

    /**
     * 将个别用户的更新发过去
     */
    public static void upDateContact(UserInfo userInfo) {
        try {
            for (String username : userInfo.getContactsList()) {
                UserSocket us = SocketTest.getUserSocketByUsername(username);
                MessageInfo updateMsg = new MessageInfo(MessageType.ONE_FRIEND_UPDATE, new Gson().toJson(userInfo));
                us.sendMessage(updateMsg);
            }
        } catch (Exception e) {
        }
    }

    /**
     * 将个别好友的新增发过去
     */
    public static void addContact(UserInfo userInfo, UserInfo friend) {
        try {
            UserSocket us = SocketTest.getUserSocketByUsername(userInfo.getUsername());
            MessageInfo ips = new MessageInfo(MessageType.ONE_FRIEND_ADD, new Gson().toJson(friend));
            us.sendMessage(ips);
        } catch (Exception e) {
        }
    }

}


class UserSocket {
    UserInfo userInfo;
    InetAddress inetAddress;
    Socket socket;

    BufferedReader br;
    PrintWriter pw;

    boolean run = true;
    long time = System.currentTimeMillis();

    public UserSocket(Socket socket) {
        this.socket = socket;
        inetAddress = socket.getInetAddress();
        UserSocket us = SocketTest.getUserSocketByIp(inetAddress.getHostAddress());
        if (us != null) {
            us.run = false;
            SocketTest.userSocketList.remove(us);
        }
        System.out.println("用户连接到服务器:ip >>>>>> " + inetAddress.getHostAddress());
        try {
            userInfo = DbUtil.getInstance().userInfoRepository.findTopByIpOrderByCookieValidityDesc(inetAddress.getHostAddress());
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (userInfo == null) {
            System.out.println("socket连接找不到对应ip的登录信息");
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;
        }
        try {
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            pw = new PrintWriter(socket.getOutputStream());
            SocketTest.userSocketList.add(this);
            SocketTest.sendContactsList(this);
            SocketTest.sendUnreadMsgList(this);

            new Thread(new Runnable() {

                @Override
                public void run() {
                    while (run) {
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        if (System.currentTimeMillis() - time > 30000) {
                            run = false;
                            break;
                        }
                    }
                }
            }).start();

            while (run && this.socket.isConnected()) {
                String string = null;
                try {
                    if ((string = br.readLine()) != null) {
                        System.out.println("收到：" + string);
                        time = System.currentTimeMillis();

                        if ("1".equals(string)) {
                            pw.println("1");
                            pw.flush();
                        } else if ("2".equals(string)) {
                            SocketTest.sendContactsList(this);
                        } else if ("3".equals(string)) {
                            pw.println("3");
                            pw.flush();
                        } else if ("4".equals(string)) {//对方收到了未读消息
                            DbUtil.getInstance().messageInfoRepository.deleteAllByToUsername(userInfo.getUsername());
                        } else {
                            try {
                                System.out.println("接收" + string);
                                onReceive(new Gson().fromJson(string, MessageInfo.class));
                            } catch (Exception e) {

                            }
                        }

                    } else {
                        break;
                    }
                } catch (Exception e) {
                    break;
                }
            }
            try {
                br.close();
            } catch (Exception e) {
            }
            try {
                pw.close();
            } catch (Exception e) {
            }

            System.out.println("用户与服务器断开连接:ip >>>>>> " + inetAddress.getHostAddress());
            SocketTest.userSocketList.remove(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 接收到用户端的消息
     */
    public void onReceive(MessageInfo msg) {

        msg.setCreateTime(System.currentTimeMillis());
        msg.setMsgId(UUID.randomUUID().toString());
        boolean onLine = false;
        SocketTest.getUserSocketByUsername(msg.getFromUsername()).sendMessage(msg);
        UserSocket us = SocketTest.getUserSocketByUsername(msg.getToUsername());
        if (us != null) {
            us.sendMessage(msg);
            onLine = true;
        }
        if (!onLine) {
            //离线消息保存到数据库
            DbUtil.getInstance().messageInfoRepository.save(msg);
        }
    }

    /**
     * 发送消息
     */
    public void sendMessage(MessageInfo msg) {
        pw.println(new Gson().toJson(msg));
        pw.flush();
    }

}
